#include "Lock.h"
#include "debug.h"

LockService::LockService(){}

LockService::~LockService(){}

uint64_t * LockService::PathToAddress(std::string &path)
{
	debug(SECTION_MDS, 10, "---> PathToAddress\n");
	uint64_t *ret = NULL;
	mtx.lock();
	if (locks.find(path) == locks.end()) {
		locks[path] = new uint64_t;
		debug(SECTION_MDS, 10, "path : %s , lock addr : %lld , val : %lld .\n", path.c_str(), locks[path], *(locks[path]));
		*(locks[path]) = 0;
		debug(SECTION_MDS, 10, "path : %s , lock addr : %lld , val : %lld .\n", path.c_str(), locks[path], *(locks[path]));
		
	}
	ret = locks[path];
	mtx.unlock();
	debug(SECTION_MDS, 10, "path : %s , lock addr : %lld .\n", path.c_str(), ret);
	debug(SECTION_MDS, 10, "<--- PathToAddress\n");
	return ret;
}

uint64_t LockService::WriteLock(uint64_t *address)
{
	debug(SECTION_MDS, 10, "---> WriteLock\n");
	uint64_t lock_value = 1;
	lock_value = lock_value << 32;
	debug(SECTION_MDS, 10, "lock addr : %lld , val : %lld .\n", address, *address);
	while (true) {
		if (__sync_bool_compare_and_swap((uint64_t *)address, 0ULL, lock_value))
			break;
	}
	debug(SECTION_MDS, 10, "lock addr : %lld , val : %lld .\n", address, *address);
	debug(SECTION_MDS, 10, "<--- WriteLock\n");
	return 1;
}

uint64_t LockService::WriteUnlock(uint64_t *address)
{
	debug(SECTION_MDS, 10, "---> WriteUnlock\n");
	debug(SECTION_MDS, 10, "lock addr : %lld , val : %lld .\n", address, *address);
	//uint32_t *p = (uint32_t *)(address + 4);
	uint32_t *p = (uint32_t *)address + 1;
	debug(SECTION_MDS, 10, "lock addr : %lld , val : %d .\n", p, *p);
	*p = 0;
	debug(SECTION_MDS, 10, "lock addr : %lld , val : %lld .\n", address, *address);
	debug(SECTION_MDS, 10, "<--- WriteUnlock\n");
	return 1;
}

uint64_t LockService::ReadLock(uint64_t *address)
{
	debug(SECTION_MDS, 10, "---> ReadLock\n");
	uint64_t preNumber = __sync_fetch_and_add((uint64_t *)address, 1ULL);
	preNumber = preNumber >> 32;
	if (preNumber == 0) {
		debug(SECTION_MDS, 10, "<--- ReadLock\n");
		return 1;
	} else {
		while(true) {
			if (__sync_bool_compare_and_swap((uint32_t *)address + 1, 0, 0))
				break;
			usleep(1);
		}
	}
	debug(SECTION_MDS, 10, "<--- ReadLock\n");
	return 1;
}


uint64_t LockService::ReadUnlock(uint64_t *address)
{
//	uint64_t lockaddress = locks_base_address + address;
	debug(SECTION_MDS, 10, "---> ReadUnlock\n");
	__sync_fetch_and_sub((uint64_t *)address, 1);
	debug(SECTION_MDS, 10, "<--- ReadUnlock\n");
	return 1;
}

